package com.qiandw.utils;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.*;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

@Slf4j
public final class SHAUtils {

    private static final String PKCS12 = "PKCS12";
    private static final String SHA256_WITH_RSA = "SHA256withRSA";
    private static final String SHA_256 = "SHA-256";

    public static String hs256WithRSA(PrivateKey privateKey, String str){
        String signStr = "";
        try {
            MessageDigest messageDigest = MessageDigest.getInstance(SHA_256);
            byte[] hash = messageDigest.digest(str.getBytes("UTF-8"));
            Signature sign = Signature.getInstance(SHA256_WITH_RSA);
            sign.initSign(privateKey);
            sign.update(hash);
            signStr = HexUtils.toHexString(sign.sign());
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException | InvalidKeyException | SignatureException e) {
            log.error("RSA 加密签名错误", e);
        }
        return signStr;
    }

    public static Boolean verifyHS256withRSA(PublicKey publicKey, String plain, String signStr){
        boolean verifyRes = false;
        try {
            MessageDigest messageDigest = MessageDigest.getInstance(SHA_256);
            byte[] hash = messageDigest.digest(plain.getBytes("UTF-8"));
            Signature sign = Signature.getInstance(SHA256_WITH_RSA);
            sign.initVerify(publicKey);
            sign.update(hash);
            verifyRes = sign.verify(HexUtils.fromHexString(signStr));
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException | InvalidKeyException | SignatureException e) {
            log.error("RSA 验证错误", e);
        }
        return verifyRes;
    }

    public static KeyStore getKS(String path, String pfxPasswd){
        KeyStore keyStore = null;
        try {
            InputStream in = new FileInputStream(path);
            keyStore = KeyStore.getInstance(PKCS12);
            keyStore.load(in, pfxPasswd.toCharArray());
        } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException e) {
            log.error("获取密钥库出错", e);
        }
        return keyStore;
    }

    public static KeyStore.PrivateKeyEntry getPKEntityWithKS(KeyStore keyStore, String alias, String passwd){
        KeyStore.PrivateKeyEntry pkEntity = null;
        try {
            pkEntity = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(passwd.toCharArray()));
        } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) {
            log.error("获取私钥实体类错误", e);
        }
        return pkEntity;
    }

    public static PrivateKey getPrivateKey(KeyStore keyStore, String alias, String passwd){
        return getPKEntityWithKS(keyStore, alias, passwd).getPrivateKey();
    }

    public static Certificate getCert(KeyStore.PrivateKeyEntry keyEntry) {
        return keyEntry.getCertificate();
    }

    public static Certificate getCert(String path){
        Certificate cert = null;
        try {
            InputStream in = new FileInputStream(path);
            CertificateFactory instance = CertificateFactory.getInstance("X.509");
            cert = instance.generateCertificate(in);
        } catch (FileNotFoundException | CertificateException e) {
            log.error("证书获取错误", e);
        }
        return cert;
    }

    public static String encodeRSA(PrivateKey privateKey, String str){
        byte[] outBytes = doFinalStr(privateKey, Cipher.ENCRYPT_MODE, str.getBytes());
        return  HexUtils.toHexString(outBytes);
    }

    public static String decodeRSA(PublicKey publicKey, String encodeStr){
        byte[] inBytes = HexUtils.fromHexString(encodeStr);
        byte[] outBytes = doFinalStr(publicKey, Cipher.DECRYPT_MODE, inBytes);
        return new String(outBytes);
    }

    private static byte[] doFinalStr(Key key, int mode, byte[] bytes){
        byte[] doFinal = new byte[0];
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(mode, key);
            doFinal = cipher.doFinal(bytes);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            log.error("RSA 加密或者签名出错", e);
        }
        return doFinal;
    }

    public static PublicKey getPubKeyWithCert(String path){
        return getCert(path).getPublicKey();
    }

    public static void main(String[] args) {
        String ksPath = "D:\\MySource\\UserJWTWebDemo\\src\\main\\resources\\jwtks.p12";
        String alias = "test";
        String certPath = "D:\\MySource\\UserJWTWebDemo\\src\\main\\resources\\jwtks.cer";
        String pfxPasswd = "123456";
        String passwd = "123456";
        //获取PubKey
        PublicKey publicKey = getPubKeyWithCert(certPath);
        //获取PrivateKey
        KeyStore keyStore = getKS(ksPath, pfxPasswd);
        PrivateKey privateKey = getPrivateKey(keyStore, alias, passwd);
        String str = "江文杰";
        //将其转换为16进制的字符串
        String signStr = hs256WithRSA(privateKey, str);
        System.out.println("RSA 签名:" +signStr);
        Boolean isVerity = verifyHS256withRSA(publicKey, str, signStr);
        System.out.println("验证签名:" +isVerity);
        //使用pk加解密
        String encodeStr = encodeRSA(privateKey, str);
        System.out.println("RSA 加密:" + encodeStr);
        String decodeStr = decodeRSA(publicKey, encodeStr);
        System.out.println("RSA 解密:" + decodeStr);
        System.exit(0);
    }
}
